#include <gtest/gtest.h>
#include "../mqserver/mq_host.hpp"

/**
 * 虚拟主机测试基类
 * 负责初始化测试环境：创建虚拟主机、交换机、队列、绑定关系，并发送测试消息
 */
class HostTest : public testing::Test
{
public:
    void SetUp() override
    {
        // 创建空参数映射
        google::protobuf::Map<std::string, std::string> empty_map;

        // 初始化虚拟主机，指定数据存储路径和数据库文件
        _host = std::make_shared<zdfmq::VirtualHost>("host1", "./data/host1/message/", "./data/host1/host1.db");

        // 创建3个持久化直连交换机（DIRECT类型）
        _host->declareExchange("exchange1", zdfmq::ExchangeType::DIRECT, true, false, empty_map);
        _host->declareExchange("exchange2", zdfmq::ExchangeType::DIRECT, true, false, empty_map);
        _host->declareExchange("exchange3", zdfmq::ExchangeType::DIRECT, true, false, empty_map);

        // 创建3个持久化队列
        _host->declareQueue("queue1", true, false, false, empty_map);
        _host->declareQueue("queue2", true, false, false, empty_map);
        _host->declareQueue("queue3", true, false, false, empty_map);

        // 为每个交换机和队列创建绑定关系（使用相同的路由键模式）
        _host->bind("exchange1", "queue1", "news.music.#");
        _host->bind("exchange1", "queue2", "news.music.#");
        _host->bind("exchange1", "queue3", "news.music.#");

        _host->bind("exchange2", "queue1", "news.music.#");
        _host->bind("exchange2", "queue2", "news.music.#");
        _host->bind("exchange2", "queue3", "news.music.#");

        _host->bind("exchange3", "queue1", "news.music.#");
        _host->bind("exchange3", "queue2", "news.music.#");
        _host->bind("exchange3", "queue3", "news.music.#");

        // 向每个队列发送3条测试消息
        _host->basicPublish("queue1", nullptr, "Hello World-1");
        _host->basicPublish("queue1", nullptr, "Hello World-2");
        _host->basicPublish("queue1", nullptr, "Hello World-3");

        _host->basicPublish("queue2", nullptr, "Hello World-1");
        _host->basicPublish("queue2", nullptr, "Hello World-2");
        _host->basicPublish("queue2", nullptr, "Hello World-3");

        _host->basicPublish("queue3", nullptr, "Hello World-1");
        _host->basicPublish("queue3", nullptr, "Hello World-2");
        _host->basicPublish("queue3", nullptr, "Hello World-3");
    }

    void TearDown() override
    {
        // 清理测试环境：删除所有创建的资源
        _host->clear();
    }

public:
    zdfmq::VirtualHost::ptr _host;
};

/**
 * 初始化测试
 * 验证：
 * 1. 交换机、队列、绑定关系是否正确创建
 * 2. 消息是否按FIFO顺序正确消费
 */
TEST_F(HostTest, init_test)
{
    // 验证交换机存在性
    ASSERT_EQ(_host->existsExchange("exchange1"), true);
    ASSERT_EQ(_host->existsExchange("exchange2"), true);
    ASSERT_EQ(_host->existsExchange("exchange3"), true);

    // 验证队列存在性
    ASSERT_EQ(_host->existsQueue("queue1"), true);
    ASSERT_EQ(_host->existsQueue("queue2"), true);
    ASSERT_EQ(_host->existsQueue("queue3"), true);

    // 验证绑定关系存在性
    ASSERT_EQ(_host->existsBinding("exchange1", "queue1"), true);
    ASSERT_EQ(_host->existsBinding("exchange1", "queue2"), true);
    ASSERT_EQ(_host->existsBinding("exchange1", "queue3"), true);

    ASSERT_EQ(_host->existsBinding("exchange2", "queue1"), true);
    ASSERT_EQ(_host->existsBinding("exchange2", "queue2"), true);
    ASSERT_EQ(_host->existsBinding("exchange2", "queue3"), true);

    ASSERT_EQ(_host->existsBinding("exchange3", "queue1"), true);
    ASSERT_EQ(_host->existsBinding("exchange3", "queue2"), true);
    ASSERT_EQ(_host->existsBinding("exchange3", "queue3"), true);

    // 验证队列1的消息按FIFO顺序消费
    zdfmq::MessagePtr msg1 = _host->basicConsume("queue1");
    ASSERT_EQ(msg1->payload().body(), std::string("Hello World-1"));
    zdfmq::MessagePtr msg2 = _host->basicConsume("queue1");
    ASSERT_EQ(msg2->payload().body(), std::string("Hello World-2"));
    zdfmq::MessagePtr msg3 = _host->basicConsume("queue1");
    ASSERT_EQ(msg3->payload().body(), std::string("Hello World-3"));
    zdfmq::MessagePtr msg4 = _host->basicConsume("queue1");
    ASSERT_EQ(msg4.get(), nullptr); // 队列为空时返回nullptr
}

/**
 * 交换机删除测试
 * 验证：删除交换机后，相关绑定关系是否被正确清理
 */
TEST_F(HostTest, remove_exchange)
{
    // 删除交换机1
    _host->deleteExchange("exchange1");

    // 验证交换机1的所有绑定关系已不存在
    ASSERT_EQ(_host->existsBinding("exchange1", "queue1"), false);
    ASSERT_EQ(_host->existsBinding("exchange1", "queue2"), false);
    ASSERT_EQ(_host->existsBinding("exchange1", "queue3"), false);
}

/**
 * 队列删除测试
 * 验证：
 * 1. 删除队列后，相关绑定关系是否被正确清理
 * 2. 已删除队列无法再消费消息
 */
TEST_F(HostTest, remove_queue)
{
    // 删除队列1
    _host->deleteQueue("queue1");

    // 验证队列1的所有绑定关系已不存在
    ASSERT_EQ(_host->existsBinding("exchange1", "queue1"), false);
    ASSERT_EQ(_host->existsBinding("exchange2", "queue1"), false);
    ASSERT_EQ(_host->existsBinding("exchange3", "queue1"), false);

    // 验证无法从已删除队列消费消息
    zdfmq::MessagePtr msg1 = _host->basicConsume("queue1");
    ASSERT_EQ(msg1.get(), nullptr);
}

/**
 * 消息确认测试
 * 验证：
 * 1. 消息按FIFO顺序消费
 * 2. 确认消息后，消息被正确标记为已消费
 */
TEST_F(HostTest, ack_message)
{
    // 消费队列1的第一条消息并确认
    zdfmq::MessagePtr msg1 = _host->basicConsume("queue1");
    ASSERT_EQ(msg1->payload().body(), std::string("Hello World-1"));
    _host->basicAck(std::string("queue1"), msg1->payload().properties().id());

    // 消费队列1的第二条消息并确认
    zdfmq::MessagePtr msg2 = _host->basicConsume("queue1");
    ASSERT_EQ(msg2->payload().body(), std::string("Hello World-2"));
    _host->basicAck(std::string("queue1"), msg2->payload().properties().id());

    // 消费队列1的第三条消息并确认
    zdfmq::MessagePtr msg3 = _host->basicConsume("queue1");
    ASSERT_EQ(msg3->payload().body(), std::string("Hello World-3"));
    _host->basicAck(std::string("queue1"), msg3->payload().properties().id());
}

// 测试程序入口
int main(int argc, char *argv[])
{
    testing::InitGoogleTest(&argc, argv);
    RUN_ALL_TESTS();
    return 0;
}